package com.samphanie.auiu.auth.controller;

import com.samphanie.auiu.auth.service.IUserAdminService;
import com.samphanie.auiu.auth.utils.UserUtil;
import com.samphanie.auiu.common.dto.CreateOrUpdateClientDto;
import com.samphanie.auiu.common.dto.CreateUserDto;
import com.samphanie.auiu.common.dto.UpdateUserDto;
import com.samphanie.auiu.common.dto.UserProfileDto;
import com.samphanie.auiu.common.utils.ApiResponse;
import com.samphanie.auiu.mbg.model.SysRole;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;

/**
 * @author ZSY
 * @email 1451691457@qq.com
 */
@RestController
@RequestMapping("/admin")
@RequiredArgsConstructor
public class UserAdminController {

    private final IUserAdminService userAdminService;
    private final JdbcClientDetailsService jdbcClientDetailsService;

    @GetMapping("/clients")
    public ApiResponse<?> findAllClients() {
        return ApiResponse.success(jdbcClientDetailsService.listClientDetails());
    }

    @PostMapping("/clients")
    public ApiResponse<?> addClient(@RequestBody CreateOrUpdateClientDto clientDto) {
        ClientDetails toAdd = userAdminService.updateClientDetails(clientDto);
        jdbcClientDetailsService.addClientDetails(toAdd);
        jdbcClientDetailsService.updateClientSecret(clientDto.getClientId(), clientDto.getClientSecret());
        return ApiResponse.success(jdbcClientDetailsService.listClientDetails().stream()
                .filter(clientDetails -> clientDetails.getClientId().equals(clientDto.getClientId()))
                .findFirst()
                .orElseThrow());
    }

    @PutMapping("/clients/{clientId}")
    public ApiResponse<?> updateClient(@PathVariable String clientId, @RequestBody CreateOrUpdateClientDto clientDto) {
        ClientDetails toUpdate = userAdminService.updateClientDetails(clientDto);
        jdbcClientDetailsService.updateClientDetails(toUpdate);
        jdbcClientDetailsService.updateClientSecret(clientId, clientDto.getClientSecret());
        return ApiResponse.success(jdbcClientDetailsService.listClientDetails().stream()
                .filter(clientDetails -> clientDetails.getClientId().equals(clientId))
                .findFirst()
                .orElseThrow());
    }

    @DeleteMapping("/clients/{clientId}")
    public ApiResponse<?> deleteClient(@PathVariable String clientId) {
        jdbcClientDetailsService.removeClientDetails(clientId);
        return ApiResponse.success(true);
    }

    @GetMapping("/users")
    public ApiResponse<?> findAllUsers(@RequestParam Map<String, Object> parameters) {
        return ApiResponse.success(userAdminService.findAllUser(parameters));
    }

    @GetMapping("/user/checkUsername")
    public ApiResponse<?> checkUsername(@RequestParam String username) {
        return ApiResponse.success(userAdminService.isUsernameExisted(username));
    }

    @GetMapping("/user/checkEmail")
    public ApiResponse<?> checkEmail(@RequestParam String email) {
        return ApiResponse.success(userAdminService.isEmailExisted(email));
    }

    @GetMapping("/user/checkMobile")
    public ApiResponse<?> checkMobile(@RequestParam String mobile) {
        return ApiResponse.success(userAdminService.isMobileExisted(mobile));
    }

    @GetMapping("/users/{username}")
    public ApiResponse<?> findByUsername(@PathVariable String username) {
        return ApiResponse.success(userAdminService.findByUsername(username)
                .map(user -> UserUtil.fromUser.apply(user))
                .orElseThrow());
    }

    @PostMapping("/user/create")
    public ApiResponse<?> createUser(@Valid @RequestBody CreateUserDto createUserDto) {
        userAdminService.validateUserUniqueFields(createUserDto.getUsername(), createUserDto.getEmail(), createUserDto.getMobile());
        return ApiResponse.success(userAdminService.createUser(createUserDto));
    }

    @PutMapping("/user/update")
    public ApiResponse<?> updateUser(@Valid @RequestBody UpdateUserDto userDto) {
        return ApiResponse.success(userAdminService.updateUser(userDto));
    }

    @DeleteMapping("/user/delete")
    public ApiResponse<?> deleteUser(@RequestBody Long[] ids) {
        return ApiResponse.success(userAdminService.deleteUser(Arrays.asList(ids)));
    }

    @PutMapping("/users/{username}")
    public ApiResponse<?> updateRoles(@PathVariable String username, @Valid @RequestBody UserProfileDto userProfileDto) {
        return ApiResponse.success(userAdminService.findByUsername(username).map(user -> {
            val toSave = user
                    .withNickname(userProfileDto.getNickname())
                    .withEmail(userProfileDto.getEmail())
                    .withMobile(userProfileDto.getMobile());
            val saved = userAdminService.saveOrUpdateUser(toSave);
            return UserUtil.fromUser.apply(saved);
        }).orElseThrow());
    }

    @PutMapping("/users/{username}/enabled")
    public ApiResponse<?> toggleUserEnabled(@PathVariable String username) {
        val user = userAdminService.toggleEnabled(username);
        return ApiResponse.success(UserUtil.fromUser.apply(user));
    }

    @GetMapping("/{username}/roles/available")
    public ApiResponse<?> getUserAvailableRoles(@PathVariable String username) {
        Set<SysRole> roles = userAdminService.findAvailableRolesByUserId(username);
        return ApiResponse.success(roles);
    }

}
